/*
 * kaka_common.h
 *
 *  Created on: 2013-8-28
 *      Author: wh
 */

#ifndef KK_COMMON_H_
#define KK_COMMON_H_

#include "cocos2d.h"
#include "cocos-ext.h"

#include <vector>
#include "../tinyxml/tinyxml.h"
#include "KKTime.h"
#include "Box2D/Box2D.h"
#include "../GLES-Render.h"

USING_NS_CC;
USING_NS_CC_EXT;

#define KKOBJECT_CREATE_METHOD(CLASS_NAME) \
		static CLASS_NAME* create(){\
			CLASS_NAME* obj = new  CLASS_NAME();\
			obj->autorelease();\
			return obj;\
		}

const char* intToString(const int value);
const char* longToString(const long value);
const char* floatToString(const float value);
const char* doubleToString(const double value);

template<class _KeyT, class _ValueT>

class KKDictionary: public cocos2d::CCObject {

public:
	typedef std::map<_KeyT, _ValueT> CCObjectMap;
	typedef typename CCObjectMap::iterator CCObjectMapIter;

protected:
	typedef std::pair<_KeyT, _ValueT> Int_Pair;
	CCObjectMap m_Map;
	bool m_bBegin;
	CCObjectMapIter m_MapIter;

public:

	KKDictionary(void) {
		m_bBegin = false;
	}

	virtual ~KKDictionary(void) {
		removeAllObjects();
	}

	std::vector<_KeyT> allKeys()
		{
			std::vector<_KeyT> tRet;
			if (m_Map.size() > 0)
			{
				CCObjectMapIter it;
				for( it = m_Map.begin(); it != m_Map.end(); ++it)
				{
					tRet.push_back(it->first);
				}
			}
			return tRet;
		}

	/// return the number of items
	unsigned int count() {
		return m_Map.size();
	}

	_ValueT valueForKey(const _KeyT& key) {

		return objectForKey(key);
	}

	_ValueT objectForKey(const _KeyT& key) ///<
			{
		CCObjectMapIter it;

		it = m_Map.find(key);

		if (it == m_Map.end()) {
			return NULL;
		}

		return it->second;
	}

	bool setObject(_ValueT pObject, const _KeyT& key) {
		std::pair<CCObjectMapIter, bool> pr;

		pr = m_Map.insert(Int_Pair(key, pObject));

		if (pr.second == true) {

			return true;
		}

		return false;
	}

	bool contains(const _KeyT& key) {
		CCObjectMapIter it;

		it = m_Map.find(key);

		if (it == m_Map.end()) {
			return false;
		}

		return true;
	}

	void removeAllObjects() {
		m_Map.clear();
	}

	void removeObjectForKey(const _KeyT& key) {
		CCObjectMapIter it;

		it = m_Map.find(key);

		if (it == m_Map.end()) //no match case
			return;

		if (it->second) {
			m_Map.erase(it);
		}
	}

	bool begin() {
		if (m_Map.size() == 0)
			return false;

		m_MapIter = m_Map.begin();
		m_bBegin = true;

		return true;
	}

	_ValueT next(_KeyT* key = NULL) {
		if (!m_bBegin)
			return NULL;

		_ValueT pObject = m_MapIter->second;

		if (m_MapIter == m_Map.end()) {
			m_bBegin = false;
		} else {
			if (key) {
				*key = m_MapIter->first;
			}

			++m_MapIter;

			if (m_MapIter == m_Map.end()) {
				m_bBegin = false;
			}
		}

		return pObject;
	}
};

template<class T = cocos2d::CCObject*>

class KKMutableArray: public cocos2d::CCObject {

private:
	std::vector<T> m_array;

public:
	typedef std::vector<T> CCObjectArray;
	typedef typename CCObjectArray::iterator CCMutableArrayIterator;
	typedef typename CCObjectArray::reverse_iterator CCMutableArrayRevIterator;

public:
	KKMutableArray(unsigned int uSize = 0) {
		if (uSize != 0)
			m_array.reserve(uSize);
	}

	virtual ~KKMutableArray(void) {
		removeAllObjects();
	}

	static KKMutableArray<T>* create() {

		KKMutableArray<T>* pArray = new KKMutableArray<T>();

		pArray->autorelease();

		return pArray;
	}

	void removeObjectsInArray(KKMutableArray<T>* pDeleteArray)
		{
			if(pDeleteArray && pDeleteArray->count())
			{
				CCMutableArrayIterator it;
				for( it = pDeleteArray->m_array.begin(); it != pDeleteArray->m_array.end(); ++it)
				{
					removeObject(*it);
				}
			}
		}

	inline unsigned int count(void) {
		return (unsigned int) m_array.size();
	}

	bool containsObject(T pObject) {
		if (m_array.empty() || (!pObject)) {
			return false;
		}

		bool bRet = false;
		CCMutableArrayIterator iter;
		for (iter = m_array.begin(); iter != m_array.end(); ++iter) {
			if (*iter == pObject) {
				bRet = true;
				break;
			}
		}

		return bRet;
	}

	T getLastObject(void) {
		CCMutableArrayRevIterator iter = rbegin();

		if (iter != m_array.rend())
			return *iter;

		return 0;
	}

	T getObjectAtIndex(unsigned int uIndex) {
		CCAssert(uIndex < count(), "");

		if (uIndex >= count()) {
			return 0;
		}

		return m_array[uIndex];
	}

	unsigned int getIndexOfObject(T pObject) {
		CCMutableArrayIterator iter;
		unsigned int i;
		for (iter = m_array.begin(), i = 0; iter != m_array.end();
				++iter, ++i) {
			if (*iter == pObject) {
				return i;
			}
		}

		return UINT_MAX;
	}

	// Adding objects
	void addObject(T pObject) {
		// make sure the pointer is not null
		if (pObject == 0) {
			return;
		}

		CCObject* obj = dynamic_cast<CCObject*>(pObject);

		if (obj) {
			obj->retain();
		}

		m_array.push_back(pObject);
	}

	void insertObjectAtIndex(T pObject, unsigned int uIndex) {
		CCAssert(uIndex <= count(), "");
		// make sure the object is not null
		if (pObject == 0) {
			return;
		}

		// add the reference of the object
		CCObject* obj = dynamic_cast<CCObject*>(pObject);

		if (obj) {
			obj->retain();
		}

		// resize the capacity if the index out of it
		if (uIndex >= m_array.capacity()) {
			m_array.reserve(uIndex + 1);
			m_array.push_back(pObject);
		} else
			// insert the object
			m_array.insert(m_array.begin() + uIndex, pObject);
	}

	// Removing objects
	void removeLastObject(bool bDeleteObject = true) {
		CCMutableArrayRevIterator it = m_array.rbegin();
		if (it != m_array.rend()) {
			if (bDeleteObject)
				(*it)->release();
			m_array.pop_back();
		}
	}

	void removeObject(T pObject, bool bDeleteObject = true) {
		if (m_array.empty() || (!pObject)) {
			return;
		}

		CCMutableArrayIterator iter;
		int i;
		for (iter = m_array.begin(), i = 0; iter != m_array.end();
				++iter, ++i) {
			if (*iter == pObject) {
				m_array.erase(iter);

				if (bDeleteObject) {

					CCObject* obj = dynamic_cast<CCObject*>(pObject);

					if (obj) {
						obj->release();
					}

				}

				break;
			}
		}
	}

	void removeObjectAtIndex(unsigned int uIndex, bool bDeleteObject = true) {
		if (m_array.empty()) {
			return;
		}

		if (bDeleteObject) {
			T pObject = m_array.at(uIndex);
			if (pObject) {
				pObject->release();
			}
		}

		m_array.erase(m_array.begin() + uIndex);
	}

	void removeAllObjects(bool bDeleteObject = true) {
		if (bDeleteObject) {
			CCMutableArrayIterator iter;
			for (iter = m_array.begin(); iter != m_array.end(); ++iter) {

				CCObject* obj = dynamic_cast<CCObject*>(*iter);

				if (obj) {
					obj->release();
				}

			}
		}

		m_array.clear();
	}

	void replaceObjectAtIndex(unsigned int uIndex, T pObject,
			bool bDeleteObject = true) {
		if (bDeleteObject && m_array[uIndex]) {
			m_array[uIndex]->release();
		}

		m_array[uIndex] = pObject;

		// add the ref
		if (pObject) {
			pObject->retain();
		}
	}

	inline CCMutableArrayIterator begin(void) {
		return m_array.begin();
	}

	inline CCMutableArrayRevIterator rbegin(void) {
		return m_array.rbegin();
	}

	CCMutableArrayIterator getLastValidIterator(void) {
		CCMutableArrayIterator iter;
		CCMutableArrayIterator ret;
		for (iter = m_array.begin(); iter != m_array.end(); ++iter) {
			ret = iter;
			if (!(*iter)) {
				break;
			}
		}

		return ret;
	}

	/*
	 * end is a keyword of lua, so should use other name
	 * to export to lua
	 */
	inline CCMutableArrayIterator endToLua(void) {
		return m_array.end();
	}

	inline CCMutableArrayIterator end(void) {
		return m_array.end();
	}

	inline CCMutableArrayRevIterator rend(void) {
		return m_array.rend();
	}

	KKMutableArray<T>* copy(void) {
		KKMutableArray* pArray = new KKMutableArray();

		pArray->m_array.assign(m_array.begin(), m_array.end());

		if (pArray->count() > 0) {
			CCMutableArrayIterator it;
			for (it = pArray->begin(); it != pArray->end(); ++it) {
				if (*it) {

					CCObject* obj = dynamic_cast<CCObject*>(*it);

					if (obj) {
						obj->retain();
					}
				}
			}
		}

		return pArray;
	}

};

class KKPoint: public cocos2d::CCObject {
public:
	float x;
	float y;
	float width;

public:

	KKPoint() {
		this->x = 0;
		this->y = 0;
		this->width = 0;
		this->autorelease();
	}
	;
	KKPoint(float x, float y) {
		this->x = x;
		this->y = y;
		this->width = 0;
		this->autorelease();
	}
	;

	bool operator>(const KKPoint &p) const {
		return x + y > p.x + p.y;
	}
	;

	bool operator<(const KKPoint &p) const {
		return x + y < p.x + p.y;
	}
	;

	bool operator==(const KKPoint &p) const {
		return x == p.x && y == p.y;
	}
	;

};

typedef KKMutableArray<KKPoint*> KKVertexArray;

typedef KKDictionary<std::string, cocos2d::CCString*> KKPropertiesDictionary;

cocos2d::ccColor3B strToColor3(const char* str);
cocos2d::ccColor4B strToColor4(const char* str);

const char* intToString(const int value);
const char* longToString(const long value);
const char* floatToString(const float value);
const char* doubleToString(const double value);

string GBKToUTF8(const string& strGBK);

std::wstring UTF8ToUnicode(const char* putf8);

std::string UnicodeToUTF8(const wchar_t* putf8);

typedef enum {
	TARGET_SCENE, TARGET_LAYER, TARGET_SPRITE, TARGET_STORYBOARD, TARGET_SOUND
} TargetType;

typedef enum {
	ACTION_EVENT,
	ACTION_SCRIPT,
	ACTION_STATUS,
	ACTION_SET_PROPERTY,
	ACTION_PARTICAL,
	ACTION_SOUND,
	ACTION_ANIM
} ActionType;

typedef float ccTime;

#endif /* KK_COMMON_H_ */
